package de.hwrberlin.remo.diagram.properties;

import java.util.Collections;
import java.util.List;

import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;

import de.hwrberlin.remo.diagram.properties.internal.Images;
import de.hwrberlin.remo.diagram.properties.internal.RemoDiagramPropertiesPlugin;
import de.hwrberlin.remo.model.KnowledgeBase;
import de.hwrberlin.remo.model.KnowledgeBaseElement;
import de.hwrberlin.remo.model.Rule;

public class RulesSection extends AbstractRemoPropertySection {
	
	private Label labelDescription;
	private StructuredViewer rulesViewer;
	
	private Button buttonUp;
	private Button buttonDown;
	
	@Override
	public void createControls(Composite parent,
			TabbedPropertySheetPage aTabbedPropertySheetPage) {
		super.createControls(parent, aTabbedPropertySheetPage);
		parent.setLayout(new FormLayout());
		
		labelDescription = getWidgetFactory().createLabel(parent, "Rule Order:");

		FormData data = new FormData();
		data.top   = new FormAttachment(0, SectionConstants.TOP_MARGIN);
		data.left  = new FormAttachment(0, SectionConstants.LABEL_INDENT);
		data.width = SectionConstants.LABEL_WIDTH;
		labelDescription.setLayoutData(data);

		// -------------------------------------------------------------

		rulesViewer = new ListViewer(parent, SWT.SINGLE | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
		rulesViewer.setContentProvider(contentProvider);
		rulesViewer.setLabelProvider(labelProvider);
		
		data = new FormData();
		data.left = new FormAttachment(labelDescription);
		data.right = new FormAttachment(50);
		data.top   = new FormAttachment(0, SectionConstants.TOP_MARGIN);
		data.height = 100;
		
		rulesViewer.getControl().setLayoutData(data);

		// -------------------------------------------------------------
		
		buttonUp = getWidgetFactory().createButton(parent, "", SWT.PUSH);
		buttonUp.addSelectionListener(upSelectionListener);
		buttonUp.setImage(RemoDiagramPropertiesPlugin.getImage(Images.UP_IMAGE));
		
		data = new FormData();
		data.left = new FormAttachment(rulesViewer.getControl());
		data.top  = new FormAttachment(30);
		buttonUp.setLayoutData(data);
		
		// ---------------------------------------------------------------
		
		buttonDown = getWidgetFactory().createButton(parent, "", SWT.PUSH);
		buttonDown.addSelectionListener(downSelectionListener);
		buttonDown.setImage(RemoDiagramPropertiesPlugin.getImage(Images.DOWN_IMAGE));
		
		data = new FormData();
		data.left = new FormAttachment(rulesViewer.getControl());
		data.top  = new FormAttachment(buttonUp, 5);
		buttonDown.setLayoutData(data);
	}
	
	@Override
	public void refresh() {
		EObject eObject = getEObject();
	
		if(eObject != null && eObject instanceof KnowledgeBase) {
			KnowledgeBase base = (KnowledgeBase) eObject;
			rulesViewer.setInput(base.getRules());
		} 
	}
	
	private IContentProvider contentProvider = new ArrayContentProvider();
	
	private LabelProvider labelProvider = new LabelProvider() {
		public String getText(Object element) {
			if(element instanceof Rule) {
				return ((Rule)element).getName();
			}
			
			return super.getText(element);
		};
		
//		public Image getImage(Object element) {
//			if(element instanceof EObject) {
//				RemoModelItemProviderAdapterFactory factory = new RemoModelItemProviderAdapterFactory();
//				Adapter adapter = factory.adapt((EObject) element, IItemLabelProvider.class);
//
//				if(adapter instanceof ItemProviderAdapter) {
//				}
//			}
//			
//			return super.getImage(element);
//		};
	};
	
	private SelectionListener downSelectionListener = new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Rule selectedRule = getSelectedRule();
			if(selectedRule == null) {
				// Do nothing
				return;
			}
			
			List<Rule> rules = getRules();
			if(rules == null || rules.isEmpty()) {
				// Do nothing
				return;
			}
			
			int index = rules.indexOf(selectedRule);
			int maxChangeableIndex = rules.size() - 2;
			
			if(index != -1 && index <= maxChangeableIndex) {
				// Swap selected rule with 
				Collections.swap(rules, index, index+1);

				// Refresh viewer
				rulesViewer.refresh();
				
				// Update model
				updateKnowledgeBase(rules);
			}
		};
	};
	
	private SelectionListener upSelectionListener = new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Rule selectedRule = getSelectedRule();
			if(selectedRule == null) {
				// Do nothing
				return;
			}
			
			List<Rule> rules = getRules();
			if(rules == null || rules.isEmpty()) {
				// Do nothing
				return;
			}
			
			int index = rules.indexOf(selectedRule);
			
			if(index != -1 && index > 0) {
				// Swap selected rule with 
				Collections.swap(rules, index, index-1);

				// Refresh viewer
				rulesViewer.refresh();
				
				// Update model
				updateKnowledgeBase(rules);
			}
		};
	};
	
	private Rule getSelectedRule() {
		ISelection selection = rulesViewer.getSelection();
		if(selection == null || selection.isEmpty() || 
				!(selection instanceof IStructuredSelection)) {
			return null;
		}
		
		IStructuredSelection structuredSelection = (IStructuredSelection) selection;
		Object selectedObject = structuredSelection.getFirstElement();

		if(selectedObject == null || !(selectedObject instanceof Rule)) {
			return null;
		}
		
		return (Rule) selectedObject;
	}
	
	@SuppressWarnings("unchecked")
	private List<Rule> getRules() {
		Object input = rulesViewer.getInput();
		if(input == null || !(input instanceof List<?>)) {
			return null;
		}
		
		return (List<Rule>) input;
	}
	
	private void updateKnowledgeBase(List<Rule> rules) {
		EObject eObject = getEObject();
		
		if(eObject != null && eObject instanceof KnowledgeBase) {
			KnowledgeBase base = (KnowledgeBase) eObject;
			
			BasicEList<KnowledgeBaseElement> ownedElements = new BasicEList<KnowledgeBaseElement>();
			ownedElements.addAll(base.getFacts());
			ownedElements.addAll(rules);
			
			editingHelper.setElements(base, ownedElements);
		} 
	}
}